<script lang="tsx" setup>
import type { Slots } from 'vue';
import { computed, ref, useSlots, watch } from 'vue';
import { UUID } from 'uuidjs';
import { message } from 'ant-design-vue';
import type { ContextmenuPopupArg, STablePaginationConfig, STableProps } from '@surely-vue/table';
import { useElementSize } from '@vueuse/core';
import STable from '@surely-vue/table';
import { get } from '@/service/api/api';

type MyColumn = {
  checked: true;
  resizable?: boolean;
  width?: number;
};

export type TableColumn = STableProps['columns'] & MyColumn;

interface Props {
  column: TableColumn[]; // 列数据
  pageSizeOptions?: string[]; // 页码选项
  isPagination?: boolean; // 是否启用和前端分页器
  rowKey?: string; // 表格唯一标识
  scroll?: { x: number | string; y: number | string }; // 滚动条配置
  dataSource?: any[] | null; // 表格数据，当dataSource存在时，url将不生效
  url?: string | null; // 请求地址
  isInitGetData?: boolean; // 是否初始化的时候请求数据
  showRowSelection?: boolean; // 是否显示行选择器
  autoGenerateUuid?: boolean; // 是否自动生成列唯一uuid
  isProductionTable?: boolean; // 是否为生产报表表格，这里会生成创建人
  tableCustomRow?: (record: any) => any; // 表格自定义行信息
  tableCustomCell?: (record: any, column: any) => any; // 表格自定义单元格信息
  resizable?: boolean; // 表格是否可伸缩
  pageSize?: number; // 表格每页显示条数
  loading?: boolean; // 表格加载状态
  createByKey?: string; // 创建人字段名,仅生产报表使用
  rowHeight?: number; // 表格高度
  summaryFixed?: boolean; // 是否固定总结栏
  showQuickJumper?: boolean; // 快速跳转
  showCardHeader?: boolean; // 是否显示卡片表头
  rowSelectionType?: 'checkbox' | 'radio'; // 行选择器类型
  defaultExpandAllRows?: boolean; // 是否默认展开所有行
  stripe?: boolean; // 是否为斑马纹表格
}

const props = withDefaults(defineProps<Props>(), {
  pageSizeOptions: () => ['50', '100', '200', '300', '500', '1000'], //  '2000', '3000', '5000', '10000'
  isPagination: true,
  rowKey: 'id',
  scroll: () => ({ x: 2000, y: 'auto' }),
  dataSource: null,
  url: null,
  isInitGetData: true,
  showRowSelection: true,
  autoGenerateUuid: false,
  isProductionTable: false,
  tableCustomRow: () => {},
  tableCustomCell: () => {},
  resizable: true,
  pageSize: 200,
  loading: false,
  createByKey: 'operator',
  rowHeight: 23,
  summaryFixed: false,
  showQuickJumper: true,
  showCardHeader: true,
  rowSelectionType: 'checkbox',
  defaultExpandAllRows: false,
  stripe: true
});

const key: string = props.autoGenerateUuid ? 'tableUuid' : props.rowKey;
interface Emits {
  (e: 'tableSelectChange', selectData: any[]): void;
  (e: 'tableRowClick', selectData: any[]): void;
  (e: 'tableRowDblclick', selectData: any[]): void;
  (e: 'tableDataLoadSucess', tableData: any[]): void;
  (e: 'paginationChange', current: number, size: number): void;
}

const emit = defineEmits<Emits>();

const slots: Slots = useSlots();

console.log('slots', slots);

const isFirstSend = ref(true); // 是否第一次请求，为了解决第一次数据获取完成后改变total赋值后又进行请求一次

const columnChecks = ref(getColumn());
const loading = ref(props.loading);
const tableData = ref<any[]>([]);
const selectedRowKeys = ref<any[]>([]);

// 合并行
function autoMergeCells(text: string, rowKey: string, index: number) {
  if (index === 0 && text === tableData.value[index - 1]?.[rowKey]) {
    return 1;
  }
  let rowSpan = 1;
  for (let i = index + 1; i < tableData.value.length; i++) {
    if (text !== tableData.value[i]?.[rowKey]) {
      break;
    }
    rowSpan += 1;
  }
  return rowSpan;
}

// 获取column 列信息
function getColumn() {
  return props.column.map(item => {
    // 伸缩行
    const resizable = item.resizable || props.resizable;
    if (!item?.customRender && item.autoMergeCells) {
      item.customRender = ({ text, index }) => {
        const obj = {
          props: {} as any
        };

        obj.props.rowSpan = autoMergeCells(text, item.key, index);
        return obj;
      };
    }
    return { ...item, resizable };
  });
}

function tableSelectChange(val: any) {
  selectedRowKeys.value = val;
  const selectData = tableData.value.filter(item => val.includes(item[key]));
  emit('tableSelectChange', selectData);
}

const pagination = ref<STablePaginationConfig>({
  current: 1,
  pageSize: props.pageSize,
  showSizeChanger: true,
  pageSizeOptions: props.pageSizeOptions,
  showQuickJumper: props.showQuickJumper,
  showTotal: (total: number) => {
    return `共${total}条`;
  }
  // total: 0
  // onChange: async (current: number, size: number) => {
  //   console.log('current', current, 'size', size);

  //   pagination.current = current;
  //   pagination.pageSize = size;
  //   emit('paginationChange', current, size);
  //   if (isFirstSend.value) return;
  //   getData();
  // }
});

watch(
  () => ({ ...pagination.value }),
  (cur, pre) => {
    if (cur.current !== pre.current || cur.pageSize !== pre.pageSize) {
      emit('paginationChange', pagination.value.current, cur.pageSize);
      getData();
    }
  }
);

function setPagination(total?: number, current?: number, pageSize?: number) {
  pagination.value.total = Number(total);
  pagination.value.current = current || pagination.value.current;
  pagination.value.pageSize = pageSize || pagination.value.pageSize;
}

// 查询参数
const searchParams = defineModel('searchParams', { required: false, type: Object, default: () => ({}) });

function selectRow(record: any) {
  selectedRowKeys.value = [record[key]];
  const selectData = tableData.value.filter(item => selectedRowKeys.value.includes(item[key]));
  emit('tableSelectChange', selectData);
}

function setSelectRows(val: any[]) {
  if (!val?.length) return;
  const arr = val.map(item => item[key]);
  tableSelectChange(arr);
}

const currentRowId = ref(null);
// 自定义行
const customRow = (record: any, index: number) => {
  function getStyle() {
    if (record[key] === currentRowId.value) {
      return '#BAEAFA';
    }
    // if (index && (index + 1) % 2 === 0) {
    //   return '#FAFAFF	';
    // }
    return '';
  }

  return {
    style: {
      'background-color': getStyle()
    },
    class: record[key] === currentRowId.value ? 'jl-table-row-selected' : '',
    onClick: () => {
      currentRowId.value = record[key];
      if (props.rowSelectionType === 'radio') {
        selectRow(record);
      }
      emit('tableRowClick', record);
    },
    ondblclick: () => {
      emit('tableRowDblclick', record);
    },
    ...props.tableCustomRow(record)
  };
};

// select
const rowSelection = computed(() => {
  return {
    selectedRowKeys: selectedRowKeys.value,
    onChange: tableSelectChange,
    type: props.rowSelectionType
  };
});

type CustomCell = {
  record: any;
  column: any;
};

// 自定义单元格
function customCell(data: CustomCell) {
  return props.tableCustomCell(data.record, data.column);
}

function setCurrentRowId(row: any) {
  console.log('key', key);

  currentRowId.value = row[key];
}

function getData(current?: number, pageSize?: number) {
  if (props.dataSource) {
    tableData.value = props.dataSource;
    isFirstSend.value = false;
    return;
  }
  if (!props.url) {
    throw new Error('表格请求地址不能为空!');
    return;
  }
  const params = {
    ...searchParams.value
  };
  if (props.isPagination) {
    if (current) {
      pagination.value.current = current;
    }
    if (pageSize) {
      pagination.value.pageSize = pageSize;
    }
    params.pageNum = pagination.value.current;
    params.pageSize = pagination.value.pageSize;
  }
  loading.value = true;
  get(props.url, params)
    .then(({ data, error }) => {
      if (!error) {
        tableData.value = [];
        const list = props.isPagination ? data.list : data;
        list.forEach((item: any, index: number) => {
          item.dataIndex = index + 1;
          if (props.autoGenerateUuid) {
            item.tableUuid = UUID.genV4().hexNoDelim;
          }
          if (props.isProductionTable) {
            item['create-founder'] = item[props.createByKey || 'operator'];
          }
        });
        if (props.isPagination) {
          pagination.value.total = data?.total || 0;
        }
        tableData.value = list;
        emit('tableSelectChange', []);
        emit('tableDataLoadSucess', tableData.value);
      } else {
        tableData.value = [];
      }
    })
    .finally(() => {
      loading.value = false;
      isFirstSend.value = false;
    });
}

const copyValue = (val: any) => {
  const input = document.createElement('input');
  input.setAttribute('readonly', 'readonly');
  input.setAttribute('value', val);
  document.body.appendChild(input);
  input.select();
  if (document.execCommand('copy')) {
    document.execCommand('copy');
    message.info('复制成功');
  }
  document.body.removeChild(input);
};
const copyClick = (args: ContextmenuPopupArg<any, any>, type: 'cell' | 'column' | 'record') => {
  if (type === 'cell') {
    if (args.column.key === 'operation') return;
    copyValue(args.text);
  } else if (type === 'column') {
    if (args.column.key === 'operation') return;
    const { dataIndex } = args.column;
    copyValue(tableData.value.map((d: any) => d[dataIndex]).join('\r\n'));
  } else {
    const record = args.record;
    copyValue(
      columnChecks.value
        .map((c: any) => (c.dataIndex ? record[c.dataIndex] : ''))
        .filter((c: any) => Boolean(c))
        .join(' ')
    );
  }
  // 3.0.1 新增
  args.hidePopup();
};

if (props.isInitGetData) {
  getData();
}

function handleResizeColumn(w: number, col: TableColumn) {
  col.width = w;
}

const tableComputedClass = computed(() => {
  let className = '';
  if (slots?.footer) {
    className += ' has-footer-table';
  }
  if (!props.isPagination) {
    className += ' no-has-pagination-table';
  }
  return className;
});

const tableFooterRef = ref(null);
const { height } = useElementSize(tableFooterRef);

const footerHeight = computed(() => {
  return `${height.value + 20 - (props.isPagination ? 0 : 40)}px`;
});

function reset() {
  tableData.value = [];
  selectedRowKeys.value = [];
  pagination.value.current = 1;
  isFirstSend.value = true;
  pagination.value.pageSize = props.pageSize;
  pagination.value.total = 0;
  currentRowId.value = null;
  isFirstSend.value = true;
}

const computedPagination = props.isPagination ? pagination : false;

watch(
  () => props.dataSource,
  val => {
    tableData.value = val as any[];
    if (props.dataSource) {
      emit('tableDataLoadSucess', tableData.value);
    }
  },
  {
    deep: true
  }
);

watch(
  () => props.loading,
  val => {
    loading.value = val;
  }
);

watch(
  () => props.column,
  val => {
    columnChecks.value = val.map(item => {
      // 伸缩行
      const resizable = item.resizable || props.resizable;
      return { ...item, resizable };
    });
  },
  {
    deep: true
  }
);

defineExpose({
  getData,
  tableSelectChange,
  tableData,
  setCurrentRowId,
  setPagination,
  reset,
  setSelectRows
});
</script>

<template>
  <ACard
    :bordered="false"
    :body-style="{ flex: 1, overflow: 'hidden' }"
    class="table-card flex-col-stretch sm:flex-1-hidden card-wrapper"
  >
    <template v-if="props.showCardHeader" #title>
      <slot name="tableTitle"></slot>
      <slot name="title"></slot>
    </template>
    <template v-if="props.showCardHeader" #extra>
      <slot name="extra"></slot>
      <TableColumnSetting v-model:columns="columnChecks" />
    </template>

    <STable
      v-model:pagination="computedPagination"
      :columns="columnChecks"
      :data-source="tableData"
      bordered
      :row-selection="props.showRowSelection ? rowSelection : null"
      size="small"
      :loading="loading"
      :row-key="key"
      :custom-row="customRow"
      :custom-cell="customCell"
      :scroll="props.scroll"
      class="h-full"
      :class="tableComputedClass"
      :row-height="props.rowHeight"
      :summary-fixed="props.summaryFixed"
      :default-expand-all-rows="defaultExpandAllRows"
      stripe
      @resize-column="handleResizeColumn"
    >
      <template v-if="slots?.footer" #footer>
        <div ref="tableFooterRef" class="table-footer">
          <slot name="footer"></slot>
        </div>
      </template>
      <!-- 右键菜单 -->
      <template #contextmenuPopup="args">
        <slot name="contextmenuPopup" :args="args">
          <ul class="popup">
            <li
              class="popup-item"
              :class="args.column.key === 'operation' && 'disabled'"
              @click="copyClick(args, 'cell')"
            >
              <!-- <CopyOutlined /> -->
              <SvgIcon local-icon="copy-text" class="text-16px"></SvgIcon>
              复制
            </li>
            <li class="popup-item" @click="copyClick(args, 'record')">
              <SvgIcon local-icon="copy-line" class="text-16px"></SvgIcon>
              复制整行
            </li>
            <li
              class="popup-item"
              :class="args.column.key === 'operation' && 'disabled'"
              @click="copyClick(args, 'column')"
            >
              <SvgIcon local-icon="copy-column" class="text-16px"></SvgIcon>
              复制整列
            </li>
            <slot name="contextmenuPopup-orter" :args="args"></slot>
          </ul>
        </slot>
      </template>

      <!-- 自定义列模板 -->
      <template v-if="slots?.bodyCell" #bodyCell="{ column: rowColumn, text, record }">
        <slot name="bodyCell" :column="rowColumn" :text="text" :record="record"></slot>
      </template>

      <!-- 自定义表头模板 -->
      <template v-if="slots?.headerCell" #headerCell="{ column: rowColumn }">
        <slot name="headerCell" :column="rowColumn"></slot>
      </template>

      <!-- 自定义过滤模板 -->
      <template
        v-if="slots?.filterDropdown"
        #customFilterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column: rowColumn }"
      >
        <slot
          name="filterDropdown"
          :set-selected-keys="setSelectedKeys"
          :selected-keys="selectedKeys"
          :confirm="confirm"
          :clear-filters="clearFilters"
          :column="rowColumn"
        ></slot>
      </template>
      <template v-if="slots?.summary" #summary>
        <slot name="summary"></slot>
      </template>
    </STable>
  </ACard>
</template>

<style lang="less" scoped>
.popup {
  min-width: 120px;

  .popup-item {
    font-size: 15px;
    cursor: pointer;
    padding: 5px 8px;
    height: 30px;
    line-height: 30px;
    box-sizing: content-box;
    position: relative;
    :first-child {
      margin-right: 8px;
      display: inline-block;
    }
    &:last-child {
      &::after {
        content: '';
        border: none;
      }
    }
    &::after {
      bottom: 0;
      left: 5%;
      position: absolute;
      content: '';
      display: inline-block;
      width: 90%;
      border: 1px dashed #646cff;
    }
    &:hover {
      background-color: var(--surely-table-row-hover-bg);
    }

    &.disabled {
      color: var(--surely-table-disabled-color);
      cursor: not-allowed;
    }
  }
}

:deep(.surely-table-wrapper) {
  &.has-footer-table {
    .ant-spin-nested-loading {
      .ant-spin-container {
        .surely-table {
          height: calc(100% - 40px - v-bind('footerHeight')) !important;
        }
      }
    }
  }
}
</style>
